/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef HMSERIALIZATION_ERROR_H
#define HMSERIALIZATION_ERROR_H

#include <string>
#include <unordered_map>
#include <napi/native_api.h>
#include "yyjson.h"
#include "securec.h"

namespace json_error {

constexpr size_t LINE_COLUMN_INFO_LEN = 128;
constexpr size_t JSON_RETAIN_STR_INFO_LEN = 512;
constexpr char* JSON_ERROR_STR_SEPARATOR = "\n";
constexpr size_t JSON_ERROR_CODE_STR_LEN = 32;

constexpr size_t NAPI_ERROR_CODE_OFFSET = 2000;
constexpr char* SPRINTF_S_ERROR_STR_SEPARATOR = "2029";
constexpr size_t YYJSON_ERROR_CODE_OFFSET = 2100;

typedef enum JsonErrorCode {
//*************--no yyjson error code begin---*************************//
    // 2000 ~ 2024 reserved for napi_status
    NAPI_PARAM_NUMBER_ERROR = 25,           // 2025
    NAPI_PARAM_TYPE_ERROR = 26,             // 2026
    NAPI_INVALID_RAW_STR = 27,              // 2027
    MEMCPY_S_ERROR = 28,                    // 2028
    SPRINTF_S_ERROR = 29,                   // 2029
    NO_YYJSON_ERROR_JSON_STR_INVALID = 30,  // 2030
    NO_YYJSON_ERROR_PARAM_INVALID = 31,     // 2031
    NO_YYJSON_ERROR_MEMORY_FAILED = 32,     // 2032
    //*************---no yyjson error code end---*************************//

    //*************---yyjson error code begin---*************************//
    // 2100 ~ 2114 reserved for yyjson_read_err
    YYJSON_CREATE_STATE_FAILED = 15,        // 2115
    YYJSON_CREATE_DOC_FAILED = 16,          // 2116
    YYJSON_DOC_TO_JSON_ERROR = 17,          // 2117
    YYJSON_INCR_READ_FAILED = 18,           // 2118
    //*************---yyjson error code end---*************************//
} JsonErrorCode;

inline const std::unordered_map<size_t, const char*> NapiErrorMessages = {
    {napi_invalid_arg, "Invalid argument passed to function."},
    {napi_object_expected, "Expected object but got different type."},
    {napi_string_expected, "Expected string but got different type."},
    {napi_name_expected, "Expected string or Symbol for property name."},
    {napi_function_expected, "Expected function but got different type."},
    {napi_number_expected, "Expected number but got different type."},
    {napi_boolean_expected, "Expected boolean but got different type."},
    {napi_array_expected, "Expected array but got different type."},
    {napi_generic_failure, "Unspecified generic failure."},
    {napi_pending_exception, "An exception is already pending."},
    {napi_cancelled, "Asynchronous operation was cancelled."},
    {napi_escape_called_twice, "Called napi_escape_handle twice on same handle."},
    {napi_handle_scope_mismatch, "Handle scope mismatch detected."},
    {napi_callback_scope_mismatch, "Callback scope mismatch detected."},
    {napi_queue_full, "Work queue is full."},
    {napi_closing, "Environment is closing and cannot complete operation."},
    {napi_bigint_expected, "Expected BigInt but got different type."},
    {napi_date_expected, "Expected Date object but got different type."},
    {napi_arraybuffer_expected, "Expected ArrayBuffer but got different type."},
    {napi_detachable_arraybuffer_expected, "Expected detachable ArrayBuffer."},
    {napi_would_deadlock, "Operation would cause deadlock."},
    {napi_create_ark_runtime_too_many_envs, "Exceeded maximum allowed environments."},
    {napi_create_ark_runtime_only_one_env_per_thread, "Only one environment per thread allowed."},
    {napi_destroy_ark_runtime_env_not_exist, "Environment does not exist for destruction."},
    {NAPI_PARAM_NUMBER_ERROR, "Native input param number error."},
    {NAPI_PARAM_TYPE_ERROR, "Expected param type error."},
    {NAPI_INVALID_RAW_STR, "The error occurs when parsing a raw string that represents a number."}
};

inline const std::unordered_map<size_t, const char*> BoundCheckErrorMessages = {
    {MEMCPY_S_ERROR, "Call memcpy_s failed. "},
    {SPRINTF_S_ERROR, "Call sprintf_s failed. "},
};

inline const std::unordered_map<size_t, const char*> YYJSONErrorMessages = {
    {YYJSON_CREATE_STATE_FAILED, "Create yyjson_incr_state failed."},
    {YYJSON_CREATE_DOC_FAILED, "Create yyjson_doc failed."},
    {YYJSON_DOC_TO_JSON_ERROR, "Write a document to JSON string failed."},
    {YYJSON_INCR_READ_FAILED, "IncrRead failed. The JSON file is incomplete."},
};

#define HANDLE_NAPI_ERROR(env, err) \
    do { \
        if ((err) != 0) { \
            HandleJsonError(env, (err), NAPI_ERROR_CODE_OFFSET, "", NapiErrorMessages); \
            return nullptr; \
        } \
    } while (0)

#define HANDLE_YYJSON_ERROR(env, err) \
    do { \
        HandleJsonError(env, (err), YYJSON_ERROR_CODE_OFFSET, "", YYJSONErrorMessages); \
        return nullptr; \
    } while (0)

#define HANDLE_YYJSON_ERROR_WITH_WRITE_ERR(env, err) \
    do { \
        HandleJsonError(env, (err).code, YYJSON_ERROR_CODE_OFFSET, (err).msg, YYJSONErrorMessages); \
        return nullptr; \
    } while (0)

#define HANDLE_YYJSON_ERROR_WITH_READ_ERR(env, errorCode, jsonStr, jsonStrLen, err) \
    do { \
        HandleYYJSONReadError(env, errorCode, jsonStr, jsonStrLen, err); \
        return nullptr; \
    } while (0)

void HandleJsonError(napi_env env, size_t errorCode, size_t offset, const char *errorMsg,
                     const std::unordered_map<size_t, const char*>& errorMessages);

void HandleBoundsCheckError(napi_env env, size_t errorCode, const char *errorMsg);

void JsonThrowHandle(napi_env env, JsonErrorCode errorCode, const char *jsonStr, size_t jsonStrLen,
                     yyjson_read_err &err);

void JsonThrowHandle(napi_env env, JsonErrorCode errorCode, const std::string &errorDescStr);

std::string GetErrorMsgByYYJSONReadErr(const char *jsonStr, size_t jsonStrLen, yyjson_read_err &err);

void HandleYYJSONReadError(napi_env env, int errorCode, const char* jsonStr, size_t jsonStrLen, yyjson_read_err& err);

} // namespace json_error

#endif // HMSERIALIZATION_ERROR_H
